package com.github.tonydeng.fmj.pool;

import cn.hutool.core.date.DateUtil;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Component
public class ThreadPoolOps implements InitializingBean {

    public static String WAIT_LIST = "plot.wait";

    public static String WORK_LIST = "plot.work.";

    public static String FINISH_LIST = "plot.finish.";

    @Autowired
    private RedisTemplate redisTemplate;

    private ValueOperations<String, Map<String, String>> operations;

    private BoundListOperations<String, Map<String, String>> waitList;

    public Long waitListIn(String workId, String size, String num, String bytes,
                           String theadNum, String buckets, String farmerKey, String poolKey,
                           String tmpDir, String tmp2Dir, String finalDir, String dCount) {
        Map<String, String> values = getValues(workId, size, num, bytes, theadNum, buckets, farmerKey, poolKey, tmpDir, tmp2Dir, finalDir, dCount);
        return waitList.rightPush(values);
    }

    public Map<String, String> getValues(String workId, String size, String num, String bytes,
                                         String theadNum, String buckets, String farmerKey, String poolKey,
                                         String tmpDir, String tmp2Dir, String finalDir, String dCount) {
        Map<String, String> values = new HashMap<>();
        values.put("workId", workId);
        values.put("size", size);
        values.put("num", num);
        values.put("bytes", bytes);
        values.put("theadNum", theadNum);
        values.put("buckets", buckets);
        values.put("farmerKey", farmerKey);
        values.put("poolKey", poolKey);
        values.put("tmpDir", tmpDir);
        values.put("tmp2Dir", tmp2Dir);
        values.put("finalDir", finalDir);
        values.put("dCount", dCount);
        values.put("startTime", DateUtil.now());
        return values;
    }

    public Map<String, String> waitListOut() {
        return waitList.leftPop();
    }

    public Long length(String key) {
        return redisTemplate.opsForList().size(key);
    }

    public boolean waitListHasElements() {
        return waitList.size() > 0;
    }

    public void workListIn(String id, String workId, String size, String num, String bytes,
                           String theadNum, String buckets, String farmerKey, String poolKey,
                           String tmpDir, String tmp2Dir, String finalDir, String dCount) {
        operations.set(WORK_LIST + id, getValues(workId, size, num, bytes, theadNum, buckets, farmerKey, poolKey, tmpDir, tmp2Dir, finalDir, dCount));
    }

    public Map<String, String> getWorkInfo(String id) {
        return operations.get(WORK_LIST + id);
    }

    public Map<String, Map<String, String>> getWorkList() {
        Set<String> keys = redisTemplate.keys(WORK_LIST + "*");
        if (keys.isEmpty()) {
            return null;
        }
        Map<String, Map<String, String>> map = new HashMap<>();
        keys.forEach( key -> {
            Map<String, String> value = operations.get(key);
            map.put(key, value);
        });
        return map;
    }

    public void clearWorkList() {
        Set<String> keys = redisTemplate.keys(WORK_LIST + "*");
        if(!keys.isEmpty()) {
            redisTemplate.delete(keys);
        }
    }

    public void workListOut(String id) {
        redisTemplate.delete(WORK_LIST + id);
    }

    public void finishListIn(String id, String workId, String size, String num, String bytes,
                           String theadNum, String buckets, String farmerKey, String poolKey,
                           String tmpDir, String tmp2Dir, String finalDir, String dCount) {
        operations.set(FINISH_LIST + id, getValues(workId, size, num, bytes, theadNum, buckets, farmerKey, poolKey, tmpDir, tmp2Dir, finalDir, dCount));
    }

    public Map<String, String> getFinishInfo(String id) {
        return operations.get(FINISH_LIST + id);
    }

    public Map<String, Map<String, String>> getFinishList() {
        Set<String> keys = redisTemplate.keys(FINISH_LIST + "*");
        if (keys.isEmpty()) {
            return null;
        }
        Map<String, Map<String, String>> map = new HashMap<>();
        keys.forEach( key -> {
            Map<String, String> value = operations.get(key);
            map.put(key, value);
        });
        return map;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        waitList = redisTemplate.boundListOps(WAIT_LIST);
        operations = redisTemplate.opsForValue();
    }
}
